package com.balloon.mall.minio.web;

import com.balloon.mall.aop.RequestSingleParam;
import com.balloon.mall.comm.ResultVO;
import com.balloon.mall.comm.ResultVOUtils;
import com.balloon.mall.minio.MinioUtil;
import com.balloon.mall.minio.entity.FileInfo;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * 文件处理 Controller
 * @author liaofuxing
 * @date 2022/08/26 14:22
 */
@RestController
public class UploadController {

    @Resource
    private MinioClient minioClient;
    @Autowired
    private MinioUtil minioUtil;

    /**
     * 文件上传
     *
     * @param file 文件对象
     * @return  ResultVO<String>
     */
    @PostMapping("/upload")
    public ResultVO<String> upload(MultipartFile file) {
        try {
            minioUtil.putObject("css", file);
            return ResultVOUtils.success(file.getOriginalFilename());
        } catch (Exception e) {
            e.printStackTrace();
            return ResultVOUtils.error(e.getMessage());
        }
    }

    /**
     * 删除文件
     *
     * @param fileName 文件名
     * @return ResultVO<Object>
     */
    @PostMapping("/remove")
    public ResultVO<Object> remove(@RequestSingleParam(value = "fileName") String fileName) {
        try {
            boolean css = minioUtil.removeObject("css", fileName);
            return ResultVOUtils.success(css);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultVOUtils.error(e.getMessage());
        }
    }

    /**
     * 获取文件URL
     *
     * @param fileName 文件名
     * @param bucketName minio 桶名
     * @return ResultVO<String>
     */
    @GetMapping("/getFileURL")
    public ResultVO<String> getFileURL(String fileName, String bucketName) {
        try {
            // 获取文件路径
            GetPresignedObjectUrlArgs css = GetPresignedObjectUrlArgs.builder().bucket(bucketName).method(Method.GET).object(fileName).build();
            String url = minioClient.getPresignedObjectUrl(css);
            System.out.println(url);
            return ResultVOUtils.success(url);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultVOUtils.error("获取文件失败");
        }
    }


    /**
     * 在线预览
     *
     * @param fileName 文件名
     * @param res response
     */
    @GetMapping("/onlinePreview")
    public void onlinePreview(@RequestParam(value = "fileName") String fileName, HttpServletResponse res) throws Exception {
        GetObjectResponse objectResponse = minioUtil.getObject("css", fileName.trim());
        res.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        res.setContentType(objectResponse.headers().get("Content-Type"));
        res.setCharacterEncoding("UTF-8");
        try (InputStream fis = objectResponse; BufferedInputStream bis = new BufferedInputStream(fis)) {
            byte[] buffer = new byte[1024];
            int i = bis.read(buffer);
            while (i != -1) {
                res.getOutputStream().write(buffer, 0, i);
                i = bis.read(buffer);
            }
            res.flushBuffer();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件下载
     *
     * @param fileName 文件名
     * @param res response
     */
    @GetMapping("/download")
    public void download(@RequestParam(value = "fileName") String fileName, HttpServletResponse res) throws Exception {
        GetObjectResponse objectResponse = minioUtil.getObject("css", fileName.trim());
        res.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        res.setContentType(objectResponse.headers().get("Content-Type"));
        res.setCharacterEncoding("UTF-8");
        try (InputStream fis = objectResponse; BufferedInputStream bis = new BufferedInputStream(fis)) {
            byte[] buffer = new byte[1024];
            int i = bis.read(buffer);
            while (i != -1) {
                res.getOutputStream().write(buffer, 0, i);
                i = bis.read(buffer);
            }
            res.flushBuffer();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取文件信息
     *
     * @param fileName 文件名
     * @return ResultVO<Object>
     */
    @GetMapping("/getFileInfo")
    public ResultVO<Object> getFileInfo(@RequestParam(value = "fileName") String fileName) {
        try {
            FileInfo fileInfo = minioUtil.getFileInfo("css", fileName);
            return ResultVOUtils.success(fileInfo);
        } catch (InvalidKeyException | ErrorResponseException | InsufficientDataException | InternalException |
                 InvalidResponseException | NoSuchAlgorithmException | XmlParserException | IOException |
                 ServerException e) {
            return ResultVOUtils.error("文件不存在");
        }
    }

    /**
     * 断点下载
     *
     * @param fileName 文件名
     * @param offset 下载字节流起
     * @param length 下载字节流止
     * @param fileSize 文件总大小
     * @param res response
     */
    @GetMapping("/parDownload")
    public void parDownload(@RequestParam(value = "fileName") String fileName, @RequestParam long offset, @RequestParam Long length, @RequestParam Long fileSize, HttpServletResponse res) throws Exception {
        // 断点下载文件,如果当次下载文件大小超过文件总大小,则代表文件总体下载完成,应该返回HTTP状态码 200
        // 如果不大于,应该返回HTTP状态码 216
        if (length.intValue() >= fileSize) {
            res.setStatus(HttpStatus.SC_OK);
        } else {
            res.setStatus(HttpStatus.SC_PARTIAL_CONTENT);
        }
        try (InputStream fis = minioUtil.getObject("css", fileName.trim(), offset, length);
             BufferedInputStream bis = new BufferedInputStream(fis);) {
            byte[] buffer = new byte[1024];
            int i = bis.read(buffer);
            while (i != -1) {
                res.getOutputStream().write(buffer, 0, i);
                i = bis.read(buffer);
            }
            res.flushBuffer();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取文件列表
     *
     * @return ResultVO<List<FileInfo>>
     */
    @ResponseBody
    @PostMapping(value = "/fileList")
    public ResultVO<List<FileInfo>> getFileList() throws Exception {
        DecimalFormat df = new DecimalFormat("0.00");
        List<Bucket> buckets = minioClient.listBuckets();
        List<FileInfo> list = new ArrayList<>(32);
        if (!buckets.isEmpty()) {
            buckets.forEach(bucket -> {
                // 得到bucket下的文件
                Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucket.name()).build());
                // 循环遍历获取每一个文件对象
                results.forEach(g -> {
                    try {
                        FileInfo fileInfo = new FileInfo();
                        fileInfo.setBucketName(bucket.name());  // 文件夹名称
                        fileInfo.setFileName(g.get().objectName());  // 文件名称
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                        fileInfo.setUpdateTime(formatter.format(g.get().lastModified().toLocalDateTime()));  // 文件上传时间
                        long size = g.get().size();
                        if (size > (1024 * 1024)) {
                            fileInfo.setFileSize(df.format(((double) size / 1024 / 1024)) + "MB");  // 文件大小，如果超过1M，则把单位换成MB
                        } else if (size > 1024) {
                            fileInfo.setFileSize(df.format(((double) size / 1024)) + "KB"); // 文件大小，如果没超过1M但是超过1000字节，则把单位换成KB
                        } else {
                            fileInfo.setFileSize(size + "bytes");  // // 文件大小，如果没超过1000字节，则把单位换成bytes
                        }
                        list.add(fileInfo);
                    } catch (ErrorResponseException | InsufficientDataException | InternalException |
                             InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException |
                             ServerException | XmlParserException e) {
                        e.printStackTrace();
                    }
                });
            });
        }
        return ResultVOUtils.success(list);
    }


}
